// Kanrong
#ifndef __H_TIMER__
#define __H_TIMER__

namespace bl{


template<class Clock> 
class tTimer
{
public:
	explicit tTimer(bool running = false) : running_(false), elapsed_(0), start_(0), count_freq_(0)
	{
		count_freq_ = Clock::GetFrequency();

		if(running)
			Start();
	}

	void Start()
	{
		start_ = Clock::GetCounter();
		running_ = true;
	}

	unsigned __int64 Stop()
	{
		unsigned __int64 stop = Clock::GetCounter();
		unsigned __int64 diff = stop - start_;
		elapsed_ += diff;
		running_ = false;
		return diff;
	}

	void Reset()
	{
		elapsed_ = 0;
		running_ = false;
	}

	double GetNanoseconds() const
	{
		unsigned __int64 runnngTime = 0;
		if(running_)
			runnngTime = Clock::GetCounter() - start_;

		return PerfCountToNanoSeconds(elapsed_ + runnngTime);
	}

	double GetMilliseconds() const
	{
		return GetNanoseconds() / 1000000;
	}

private:
	double PerfCountToNanoSeconds(unsigned __int64 perfCount) const
	{
		return (static_cast<double>(perfCount) / static_cast<double>(count_freq_)) *
			static_cast<double>(1000000000.0);
	}

	bool running_;
	unsigned __int64 start_;
	unsigned __int64 elapsed_;
	unsigned __int64 count_freq_;
};

class LowResolutionClock
{
public:
	inline static unsigned __int64 GetCounter()
	{
		return ::GetTickCount();
	}

	inline static unsigned __int64 GetFrequency()
	{
		return 1000;
	}
};

class HighResolutionClock
{
public:
	inline static unsigned __int64 GetCounter()
	{
		__asm rdtsc
	}

	inline static unsigned __int64 GetFrequency()
	{
		static unsigned __int64 rdtscFreq = 0;
		if(rdtscFreq == 0)
		{
			rdtscFreq = GetRdtscFrequency();
			if(rdtscFreq <=1 )
				rdtscFreq = 1;
		}
		return rdtscFreq;
	}

private:
	inline static unsigned __int64 GetRdtscFrequency()
	{
		//
		// Get elapsed RDTSC and elapsed QPC over same time period
		//

		// compute length of time period to measure
		__int64 freq_qpc = 0;  // ticks per second
		QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER*>(&freq_qpc));

		// fraction of second to run timers for; tradeoff b/w speed and accuracy;
		// 1/1000 (1 msec) seems like good tradeoff
		__int64 interval_qpc = freq_qpc / 1000;

		// get timer values over same time period
		__int64 begin_qpc = 0;
		__int64 end_qpc = 0;

		QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&begin_qpc));

		__int64 begin_rdtsc = HighResolutionClock::GetCounter();

		// spin and protect against infinite loop, if QPC does something wacky
		int count = 0;
		const int count_max = 50000;
		do {
			QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&end_qpc));
			++count;
		} while ((end_qpc - begin_qpc) < interval_qpc  &&  count < count_max);

		QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&end_qpc));
		__int64 end_rdtsc = HighResolutionClock::GetCounter();


		//
		// Compute RDTSC frequency from QPC frequency
		//

		__int64 diff_qpc = end_qpc - begin_qpc;
		__int64 diff_rdtsc = end_rdtsc - begin_rdtsc;

		__int64 freq_rdtsc = freq_qpc * diff_rdtsc / diff_qpc;

		return freq_rdtsc;
	}
};

class SysHighResolutionClock
{
public:
	inline static unsigned __int64 GetCounter()
	{
		__int64 counter;
		QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&counter));
		return counter;
	}

	inline static unsigned __int64 GetFrequency()
	{
		__int64 freq;
		QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER*>(&freq));
		return freq;
	}

};

typedef tTimer<SysHighResolutionClock> Timer;


}

#endif